#include <gtest/gtest.h>
#include "Thread/semaphore.h"
#include <thread>
#include <vector>
#include <atomic>

using namespace toolkit;
using namespace std;

class SemaphoreTest : public testing::Test {
protected:
    semaphore sem;
};

TEST_F(SemaphoreTest, BasicPostWait) {
    // 测试基本post/wait功能
    thread t([this]() {
        this_thread::sleep_for(chrono::milliseconds(100));
        sem.post();
    });
    
    sem.wait();
    t.join();
    SUCCEED();
}

TEST_F(SemaphoreTest, MultiplePost) {
    const int count = 10;
    atomic_int finished(0);
    
    thread producer([this, count]() {
        for (int i = 0; i < count; ++i) {
            sem.post();
            this_thread::sleep_for(chrono::milliseconds(10));
        }
    });
    
    vector<thread> consumers;
    for (int i = 0; i < count; ++i) {
        consumers.emplace_back([this, &finished]() {
            sem.wait();
            ++finished;
        });
    }
    
    producer.join();
    for (auto& t : consumers) {
        t.join();
    }
    
    EXPECT_EQ(finished.load(), count);
}

TEST_F(SemaphoreTest, InitialCount) {
    semaphore init_sem(5); // 初始计数5
    atomic_int count(0);
    
    vector<thread> threads;
    for (int i = 0; i < 5; ++i) {
        threads.emplace_back([&init_sem, &count]() {
            init_sem.wait();
            ++count;
        });
    }

    init_sem.post(5);
    // 立即检查，不需要post就应该能通过
    for (auto& t : threads) {
        t.join();
    }
    EXPECT_EQ(count.load(), 5);
}

TEST_F(SemaphoreTest, MultiPostSingleWait) {
    const int post_count = 10;
    atomic_int wait_count(0);
    
    thread poster([this, post_count]() {
        for (int i = 0; i < post_count; ++i) {
            sem.post();
            this_thread::sleep_for(chrono::milliseconds(10));
        }
    });
    
    thread waiter([this, &wait_count, post_count]() {
        for (int i = 0; i < post_count; ++i) {
            sem.wait();
            ++wait_count;
        }
    });
    
    poster.join();
    waiter.join();
    
    EXPECT_EQ(wait_count.load(), post_count);
}

TEST_F(SemaphoreTest, ConcurrentAccess) {
    const int thread_count = 20;
    atomic_int counter(0);
    
    vector<thread> producers;
    vector<thread> consumers;
    
    for (int i = 0; i < thread_count; ++i) {
        producers.emplace_back([this]() {
            this_thread::sleep_for(chrono::milliseconds(10));
            sem.post();
        });
        
        consumers.emplace_back([this, &counter]() {
            sem.wait();
            ++counter;
        });
    }
    
    for (auto& t : producers) {
        t.join();
    }
    for (auto& t : consumers) {
        t.join();
    }
    
    EXPECT_EQ(counter.load(), thread_count);
}